#include "fm33le0xx_fl.h"
#include "main.h"
#include "k_line.h"

#define PACK_FIRST_BYTE 'Y'
#define PACK_SECOND_BYTE 'D'
#define PACK_END_FIRSE_BYTE 'K'
#define PACK_END_SECOND_BYTE 'J'

#define FRAME_MIN_LEN 7
#define FRAME_MAX_LEN 30
#define RX_BUF_SIZE FRAME_MAX_LEN
#define RX_FIFO_LENGTH (FRAME_MAX_LEN * 2)

typedef struct {
    volatile uint8_t fifo_data[RX_FIFO_LENGTH];
    volatile uint8_t start_pos;
    volatile uint8_t end_pos; // 指向下一个要写入的数
} rx_fifo_t;

static rx_fifo_t rx_fifo_data;
static volatile uint8_t tx_in_idle = 1;
static k_frame_recv_cb_t frame_recv_callback;

void UART0_IRQHandler(void) {
    if (UART0->ISR & UART_ISR_RXBF_Msk) { //接收中断处理
        uint8_t pos_now = rx_fifo_data.end_pos + 1;
        if (pos_now == RX_FIFO_LENGTH) {
            pos_now = 0;
        }
        // SKIP WHEN FIFO FULL
        if (pos_now == rx_fifo_data.start_pos) { 
            volatile uint8_t unused = FL_UART_ReadRXBuff(UART0);
            return ;
        }
        rx_fifo_data.fifo_data[rx_fifo_data.end_pos] = FL_UART_ReadRXBuff(UART0);
        rx_fifo_data.end_pos = pos_now;
    } else if(UART0->ISR & UART_ISR_TXSE_Msk) { // 发送中断处理
        UART0->ISR = UART_ISR_TXSE_Msk; // 清除 TXSE
        tx_in_idle = 1;
    }
}

static uint32_t deal_uart_buffer(uint8_t* buffer, uint32_t data_length) {
    uint8_t* deal_ptr = (uint8_t *)buffer;
    uint32_t packet_len = 0;

    while (data_length > 1) {
		if(deal_ptr[0] == PACK_FIRST_BYTE && deal_ptr[1] == PACK_SECOND_BYTE) {
            break ;
        }
        deal_ptr += 1;
        data_length -= 1;
    }
    if (data_length < FRAME_MIN_LEN) {
        goto exit;
    }
    packet_len = deal_ptr[3] + 7;
    if (packet_len > RX_BUF_SIZE || packet_len < FRAME_MIN_LEN) {
        // skip error length, find next head
        packet_len = 2;
        goto exit;
    }
     if (data_length < packet_len) {
        packet_len = 0;
        goto exit;
    }

    uint8_t sum = 0x00;
    for (uint8_t i = 2; i < packet_len - 3; i++) {
        sum += deal_ptr[i];
    }

    if (sum == deal_ptr[packet_len - 3]) {
        if (frame_recv_callback) {
            frame_recv_callback(deal_ptr[2], &deal_ptr[4], deal_ptr[3]);
        }
    }

exit:
    deal_ptr += packet_len;
    return deal_ptr - buffer;
}

void k_line_init(k_frame_recv_cb_t recv_cb) {
    FL_UART_ClearFlag_TXShiftBuffEmpty(UART0);
    FL_UART_EnableIT_TXShiftBuffEmpty(UART0);     // 使能发送中断
    FL_UART_ClearFlag_RXBuffFull(UART0);
    FL_UART_EnableIT_RXBuffFull(UART0);           // 使能接收中断
    FL_UART_EnableTX(UART0);
    FL_UART_EnableRX(UART0);

    rx_fifo_data.start_pos = 0;
    rx_fifo_data.end_pos = 0;

    tx_in_idle = 1;

    frame_recv_callback = recv_cb;
}

void k_line_deinit() {

}

void k_line_uart_write(const uint8_t* buffer, uint32_t length) {
    while (tx_in_idle == 0);
    tx_in_idle = 0;
    FL_DMA_ConfigTypeDef DMA_ConfigStruct = {0};
    DMA_ConfigStruct.memoryAddress = (uint32_t)buffer;
    DMA_ConfigStruct.transmissionCount = length - 1;
    FL_DMA_StartTransmission(DMA, &DMA_ConfigStruct, FL_DMA_CHANNEL_2);
}

void k_line_deal_rx_fifo_data() {
    static uint8_t buffer_stash[RX_BUF_SIZE];
    static uint8_t buffer_total_len = 0;

    uint8_t num = 0;
    uint8_t used_size;
    
    while (rx_fifo_data.start_pos != rx_fifo_data.end_pos) {
        uint8_t end_pos = rx_fifo_data.end_pos;
        if (end_pos < rx_fifo_data.start_pos) {
            num = RX_FIFO_LENGTH - rx_fifo_data.start_pos;
        } else {
            num = end_pos - rx_fifo_data.start_pos;
        }
        if (buffer_total_len + num > RX_BUF_SIZE) {
            num = RX_BUF_SIZE - buffer_total_len;
        }
        memcpy(buffer_stash + buffer_total_len, (void *)(rx_fifo_data.fifo_data + rx_fifo_data.start_pos), num);
        buffer_total_len += num;
        
        if (rx_fifo_data.start_pos + num >= RX_FIFO_LENGTH) {
            rx_fifo_data.start_pos = rx_fifo_data.start_pos + num - RX_FIFO_LENGTH;
        } else {
            rx_fifo_data.start_pos += num;
        }

        do {
            used_size = deal_uart_buffer(buffer_stash, buffer_total_len);
            buffer_total_len -= used_size;
            memmove(buffer_stash, buffer_stash + used_size, buffer_total_len);
        } while ((buffer_total_len > 1 && used_size != 0));
    }
}

void k_line_write_bytes(uint16_t cmd, const uint8_t* frame, uint32_t len) {
    static uint8_t out_buf[FRAME_MAX_LEN];
    uint32_t out_len = FRAME_MIN_LEN + len;
    if (out_len > FRAME_MAX_LEN) {
        return ;
    }
    // 等待DMA发送完成
    while (tx_in_idle == 0);

    out_buf[0] = 'Y';
    out_buf[1] = 'D';
    out_buf[2] = cmd; 
    out_buf[3] = len;
    memcpy(&out_buf[4], frame, len);
    uint16_t crc16_result = 0;
    out_buf[4 + len] = 0;
    for (uint8_t i = 2; i < 4 + len; i++) {
        out_buf[4 + len] += out_buf[i];
    }
    out_buf[5 + len] = 'K';
    out_buf[6 + len] = 'J';
    k_line_uart_write(out_buf, out_len);
}
